<?php

namespace App\Workers;

use App\Services\CollegeDataUpdateInsertSpiderService;
use Workerman\Worker;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

class CollegeDataUpdateInsertSpiderWorker
{
    protected static $logger;
    protected static $startTime;
    protected static $memoryPeak = 0;

    public static function run(Worker $worker, $limit = 0)
    {
        self::initLogger();
        self::registerSignalHandlers();

        $worker->onWorkerStart = function($worker) use ($limit) {
            self::$startTime = microtime(true);
            self::logSystemInfo();

            try {
                self::$logger->info("Worker启动", [
                    'pid' => getmypid(),
                    'limit' => $limit
                ]);

                $spider = new CollegeDataUpdateInsertSpiderService();
                $spider->setLimit($limit);
                $spider->crawlAllColleges();

                self::logCompletionStats();
            } catch (\Throwable $e) {
                self::handleFatalError($e, $worker);
            }
        };

        $worker->onWorkerStop = function() {
            self::$logger->info("Worker停止", [
                'uptime' => round(microtime(true) - self::$startTime, 2).'s',
                'memory_peak' => round(memory_get_peak_usage(true) / 1024 / 1024, 2).'MB'
            ]);
        };

        $worker->onWorkerReload = function() {
            self::$logger->info("Worker重载", [
                'memory_usage' => round(memory_get_usage(true) / 1024 / 1024, 2).'MB'
            ]);
        };
    }

    protected static function initLogger()
    {
        if (!self::$logger) {
            $logDir = dirname(__DIR__, 2) . '/storage/logs';
            self::$logger = new Logger('艺考专业分数采集Worker');
            self::$logger->pushHandler(new StreamHandler($logDir.'/yikao-special-score-worker.log'));
        }
    }

    protected static function registerSignalHandlers()
    {
        if (function_exists('pcntl_signal')) {
            pcntl_signal(SIGTERM, function() {
                self::$logger->info("收到SIGTERM信号，准备退出");
                exit(0);
            });
            pcntl_signal(SIGINT, function() {
                self::$logger->info("收到SIGINT信号，准备退出");
                exit(0);
            });
        }
    }

    protected static function logSystemInfo()
    {
        self::$logger->info("系统信息", [
            'php_version' => PHP_VERSION,
            'os' => PHP_OS,
            'memory_limit' => ini_get('memory_limit')
        ]);
    }

    protected static function logCompletionStats()
    {
        $uptime = round(microtime(true) - self::$startTime, 2);
        $memoryUsage = round(memory_get_usage(true) / 1024 / 1024, 2);
        $memoryPeak = round(memory_get_peak_usage(true) / 1024 / 1024, 2);

        self::$logger->info("采集任务完成", [
            'uptime' => $uptime.'s',
            'memory_usage' => $memoryUsage.'MB',
            'memory_peak' => $memoryPeak.'MB'
        ]);
    }

    protected static function handleFatalError(\Throwable $e, Worker $worker)
    {
        self::$logger->error("Worker运行异常", [
            'error' => $e->getMessage(),
            'file' => $e->getFile(),
            'line' => $e->getLine(),
            'trace' => $e->getTraceAsString(),
            'memory_usage' => round(memory_get_usage(true) / 1024 / 1024, 2).'MB'
        ]);

        $worker->stop();
    }

    protected static function checkMemoryUsage()
    {
        $usage = memory_get_usage(true);
        if ($usage > self::$memoryPeak) {
            self::$memoryPeak = $usage;
        }

        $limit = ini_get('memory_limit');
        $limitBytes = self::convertToBytes($limit);
        $threshold = $limitBytes * 0.8;

        if ($usage > $threshold) {
            self::$logger->warning("内存使用接近上限", [
                'usage' => round($usage / 1024 / 1024, 2).'MB',
                'limit' => $limit
            ]);
        }
    }

    protected static function convertToBytes($value)
    {
        $unit = strtolower(substr($value, -1));
        $value = (int)$value;

        switch($unit) {
            case 'g': return $value * 1024 * 1024 * 1024;
            case 'm': return $value * 1024 * 1024;
            case 'k': return $value * 1024;
            default: return $value;
        }
    }
}
